//
//	File: MaterialProperties.cpp
//

// Implementation of the material properties.
#include "../OyDirect3D9.h"
#include "MaterialProperties.h"
#include "MaterialRenderer.h"
#include "../DX9Shader/DX9VertexShader.h"
#include "../DX9Shader/DX9PixelShader.h"


#define D3DCOLOR_A(VALUE)		(BYTE)((VALUE & 0xFF000000)>>24)
#define D3DCOLOR_R(VALUE)		(BYTE)((VALUE & 0x00FF0000)>>16)
#define D3DCOLOR_G(VALUE)		(BYTE)((VALUE & 0x0000FF00)>>8)
#define D3DCOLOR_B(VALUE)		(BYTE)(VALUE & 0x000000FF)


// ColorProperty
void ColorProperty::Apply( D3DCOLOR & dest ) const
{
	switch( op_ )
	{
		case CO_Replace :	
			dest = color_;	
			break;
		case CO_Add :
			dest = D3DCOLOR_ARGB(	D3DCOLOR_A(dest) + D3DCOLOR_A(color_), 
									D3DCOLOR_R(dest) + D3DCOLOR_R(color_),
									D3DCOLOR_G(dest) + D3DCOLOR_G(color_),
									D3DCOLOR_B(dest) + D3DCOLOR_B(color_) 
									);

			break;
		case CO_Multiply :	
			dest = D3DCOLOR_COLORVALUE(	D3DCOLOR_R(dest)/255.0f * D3DCOLOR_R(color_)/255.0f,
										D3DCOLOR_G(dest)/255.0f * D3DCOLOR_G(color_)/255.0f,
										D3DCOLOR_B(dest)/255.0f * D3DCOLOR_B(color_)/255.0f,
										D3DCOLOR_A(dest)/255.0f * D3DCOLOR_A(color_)/255.0f
										);
			break;
	}
}



D3DCOLOR AmbientColorProperty::current_;
void AmbientColorProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_AMBIENT, current_);
	GetMaterialRenderer()->IncreasePropertyNum();
}

/*
// DiffuseProperty
D3DCOLOR DiffuseProperty::current_;
void DiffuseProperty::Begin() const
{
	return;
#if 0
	Apply( current_ );
	//glMaterialfv( GL_FRONT, GL_DIFFUSE, current_.GLarray() );
	D3DMATERIAL9 *pMaterial = HR3D_Config()->GetMaterial();
	pMaterial->Diffuse = D3DCOLORVALUE(current_);
	RI->SetMaterial(pMaterial);
	Application::Instance().AddProperty();
#endif
}


// SpecularProperty
D3DXVECTOR4 SpecularProperty::current_;
void SpecularProperty::Begin() const
{
	return;
#if 0
	Apply( current_ );
	//glMaterialfv( GL_FRONT, GL_SPECULAR, current_.GLarray() );
	D3DMATERIAL9 *pMaterial = HR3D_Config()->GetMaterial();
	pMaterial->Specular = D3DCOLORVALUE(current_);
	RI->SetMaterial(pMaterial);
	Application::Instance().AddProperty();
#endif
}


// EmissiveProperty
D3DXVECTOR4 EmissiveProperty::current_;
void EmissiveProperty::Begin() const
{
	return;
#if 0
	Apply( current_ );
	//glMaterialfv( GL_FRONT, GL_EMISSION, current_.GLarray() );
	D3DMATERIAL9 *pMaterial = HR3D_Config()->GetMaterial();
	pMaterial->Emissive = D3DCOLORVALUE(current_);
	RI->SetMaterial(pMaterial);
	Application::Instance().AddProperty();
#endif
}

void EmissiveProperty::End() const
{
	return;
#if 0
	// this one is reset to its default value (black)
	//const static float BLACK[4] = { 0.f, 0.f, 0.f, 0.f };
	//glMaterialfv( GL_FRONT, GL_EMISSION, BLACK );
	D3DMATERIAL9 *pMaterial = HR3D_Config()->GetMaterial();
	pMaterial->Emissive = D3DCOLORVALUE(0, 0, 0, 0);
	RI->SetMaterial(pMaterial);
#endif
}


// ShininessProperty
void ShininessProperty::Begin() const
{
	return;
#if 0
	//glMaterialf( GL_FRONT, GL_SHININESS, value_ );
	D3DMATERIAL9 *pMaterial = HR3D_Config()->GetMaterial();
	pMaterial->Power = value_;
	RI->SetMaterial(pMaterial);
	Application::Instance().AddProperty();
#endif
}
*/

// OyMaterialProperty
// If Lighting is disable, OyMaterialProperty will unusable
void OyMaterialProperty::Begin() const
{
	OyMaterial material_ = GetRenderDevice()->GetSkinManager()->GetMaterial(material_ID);
	D3DMATERIAL9 mat = {
		material_.cDiffuse.fR, material_.cDiffuse.fG, material_.cDiffuse.fB, material_.cDiffuse.fA,
		material_.cAmbient.fR, material_.cAmbient.fG, material_.cAmbient.fB, material_.cAmbient.fA,
		material_.cSpecular.fR, material_.cSpecular.fG, material_.cSpecular.fB, material_.cSpecular.fA,
		material_.cEmissive.fR, material_.cEmissive.fG, material_.cEmissive.fB, material_.cEmissive.fA,
		material_.fPower
	};
	GetMaterialRenderer()->GetD3DDevice()->SetMaterial( &mat );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_AMBIENT, GetOyD3D9Config()->m_GlobalAmbientColor);

	GetMaterialRenderer()->IncreasePropertyNum();
}
void OyMaterialProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_AMBIENT,0);
}


// TextureProperty
void TextureProperty::Begin() const
{
	if( texture_ID != 0xFFFFFFFF )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetTexture( unit_, (LPDIRECT3DTEXTURE9)GetRenderDevice()->GetSkinManager()->GetOyTextureData(texture_ID) );
		GetMaterialRenderer()->IncreasePropertyNum();
	}
}
void TextureProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetTexture( unit_, NULL );
}



// DisableTextureProperty
void DisableTextureProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetTexture( unit_, NULL );
	GetMaterialRenderer()->IncreasePropertyNum();
}



// AlphaBlendOpProperty
void AlphaBlendOpProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_BLENDOP, op_);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void AlphaBlendOpProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
}


// AlphaBlendProperty
void AlphaBlendProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_SRCBLEND, src_);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_DESTBLEND, dst_);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void AlphaBlendProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
}

// AlphaBlendAlphaProperty
void AlphaBlendAlphaProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, TRUE );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_BLENDOPALPHA, op_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_SRCBLENDALPHA, src_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_DESTBLENDALPHA, dst_ );
	GetMaterialRenderer()->IncreasePropertyNum();
}
void AlphaBlendAlphaProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, FALSE );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_SRCBLENDALPHA, D3DBLEND_ONE );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO );
}


//AlphaTestFuncProperty
void AlphaTestFuncProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHAFUNC, func_);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void AlphaTestFuncProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS);
}

// AlphaTestRefProperty
void AlphaTestRefProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHAREF, ref_);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void AlphaTestRefProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ALPHAREF, 0);
}

// StencilProperty
void StencilProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILFUNC, func_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILFAIL, fail_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILZFAIL, zfail_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILPASS, pass_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILREF, ref_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILMASK, mask_ );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILWRITEMASK, writemask_ );
	GetMaterialRenderer()->IncreasePropertyNum();
}
void StencilProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILREF, 0 );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILMASK, 0xFFFFFFFF );
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_STENCILWRITEMASK, 0xFFFFFFFF );

}

// TextureFactorProperty
void TextureFactorProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_TEXTUREFACTOR, value_ );
	GetMaterialRenderer()->IncreasePropertyNum();
}

void TextureFactorProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_TEXTUREFACTOR, 0xFFFFFFFF );
}



// DepthEnableProperty
void DepthEnableProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_ZENABLE, ZBufferType );
	GetMaterialRenderer()->IncreasePropertyNum();
}
void DepthEnableProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
}


// DepthBiasProperty
void DepthBiasProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_DEPTHBIAS , *(DWORD*)(&bias_));
	GetMaterialRenderer()->IncreasePropertyNum();
}
void DepthBiasProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_DEPTHBIAS , 0);
}


// DepthFuncProperty
void DepthFuncProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ZFUNC, func_);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void DepthFuncProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
}


// ColorMaskProperty
void ColorMaskProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, MaskValue);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void ColorMaskProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, 0x0000000F);
}


// CullingModeProperty
void CullingModeProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_CULLMODE, cull_);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void CullingModeProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}


// ShaderProperty
void ShaderProperty::Begin() const
{
	if( pVSShader )
		GetMaterialRenderer()->GetD3DDevice()->SetVertexShader( pVSShader->GetShaderInterface() );
	if( pPSShader )
		GetMaterialRenderer()->GetD3DDevice()->SetPixelShader( pPSShader->GetShaderInterface() );
	GetMaterialRenderer()->IncreasePropertyNum();
}
void ShaderProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetVertexShader( NULL );
	GetMaterialRenderer()->GetD3DDevice()->SetPixelShader( NULL );
}


// EnableStateProperty
void EnableStateProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(cap_, TRUE);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void EnableStateProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(cap_, FALSE);
}


// DisableStateProperty
void DisableStateProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(cap_, FALSE);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void DisableStateProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(cap_, TRUE);
}


// LineDrawingProperty
void LineDrawingProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void LineDrawingProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
}

//LightingDisableProperty
void LightingDisableProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_LIGHTING, !lightingDisable_);
	GetMaterialRenderer()->IncreasePropertyNum();
}
void LightingDisableProperty::End() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetRenderState(D3DRS_LIGHTING, TRUE);
}

// SamplerStateProperty
void SamplerStateProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, Value_ );
	GetMaterialRenderer()->IncreasePropertyNum();
}
void SamplerStateProperty::End() const
{
	if( Type_ == D3DSAMP_ADDRESSU )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, D3DTADDRESS_WRAP );
	}
	else if( Type_ == D3DSAMP_ADDRESSV )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, D3DTADDRESS_WRAP );
	}
	else if( Type_ == D3DSAMP_ADDRESSW )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, D3DTADDRESS_WRAP );
	}
	else if( Type_ == D3DSAMP_MAGFILTER || Type_ == D3DSAMP_MINFILTER )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, D3DTEXF_POINT );
	}
	else if( Type_ == D3DSAMP_MIPFILTER )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, D3DTEXF_NONE );
	}
	else if( Type_ == D3DSAMP_BORDERCOLOR )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, 0x00000000 );
	}
	else if( Type_ == D3DSAMP_MIPMAPLODBIAS  || Type_ == D3DSAMP_MAXMIPLEVEL ||
		Type_ == D3DSAMP_SRGBTEXTURE || Type_ == D3DSAMP_ELEMENTINDEX ||
		Type_ == D3DSAMP_DMAPOFFSET )
	{
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, 0 );
	}
	else if( Type_ == D3DSAMP_MAXANISOTROPY )
		GetMaterialRenderer()->GetD3DDevice()->SetSamplerState( Sampler_, Type_, 1 );

}

// TextureStageStateProperty
void TextureStageStateProperty::Begin() const
{
	GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, Value_ );
	GetMaterialRenderer()->IncreasePropertyNum();
}
void TextureStageStateProperty::End() const
{
	switch( Type_ )
	{
	case D3DTSS_COLOROP:
		if( Stage_ == 0)
			GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTOP_MODULATE );
		else
			GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTOP_DISABLE );
		break;

	case D3DTSS_COLORARG1:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTA_TEXTURE );
		break;

	case D3DTSS_COLORARG2:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTA_CURRENT );
		break;

	case D3DTSS_ALPHAOP:
		if( Stage_ == 0)
			GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTOP_SELECTARG1 );
		else
			GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTOP_DISABLE );
		break;

	case D3DTSS_ALPHAARG1:
		if( Stage_ == 0)
			GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTA_TEXTURE );
		else
			GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTA_TEXTURE );
		break;

	case D3DTSS_ALPHAARG2:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTA_CURRENT );
		break;

	case D3DTSS_BUMPENVMAT00:
	case D3DTSS_BUMPENVMAT01:
	case D3DTSS_BUMPENVMAT10:
	case D3DTSS_BUMPENVMAT11:
	case D3DTSS_BUMPENVLSCALE:
	case D3DTSS_BUMPENVLOFFSET:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, 0 );
		break;

	case D3DTSS_TEXCOORDINDEX:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, Stage_ );
		break;

	case D3DTSS_TEXTURETRANSFORMFLAGS:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTTFF_DISABLE );
		break;

	case D3DTSS_COLORARG0:
	case D3DTSS_ALPHAARG0:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTA_CURRENT );
		break;

	case D3DTSS_RESULTARG:
		GetMaterialRenderer()->GetD3DDevice()->SetTextureStageState( Stage_, Type_, D3DTA_CURRENT );
		break;

	default:
		break;
	}
}




